#ifndef __GPU2BWT_API_H__
#define __GPU2BWT_API_H__

/**
 * the interface for CPU program
 * */

#include"2BWTSearch.h"
#include "mian_util.h"
#include "cuda_header.h"
#include "buffer.h"
#include "ReadSet.h"
#include "QuerySet.h"
#include "GPU2BWT_kernel.h"
#include "SAMatch.h"
#include <thrust/sort.h>
#include <vector>


using namespace std;


/**
 * @return the number of alignment
 * @param h_sa the output sa range, the memory should be allocated in advance
 * @param numSA the number of sa
 * @param h_query the input query (encoded)
 * @param numQuery
 * @param d_bwt
 * @param d_revbwt
 * @param GPUMemBuf it should be already allocated
 * */
//uint64 GPUExactMatch(uint3* h_sa, uint32* numSa,
//			unsigned int * h_query, const unsigned int numQuery,
//			BWT *d_bwt, BWT *d_revbwt, st_MemoryBuf* GPUMemBuf);

class GPU2BWT {
public:
	GPU2BWT() : _GPUBufSize(0), _GPUResultBufSize(0) {};
	~GPU2BWT();
	GPU2BWT(BWT* h_bwt, BWT* h_revbwt, const unsigned long GPUBufSize);
	GPU2BWT(BWT* h_bwt, BWT* h_revbwt);

	/**
 	* exact match, 1-mismatch, and 2-mismatch
 	* @return the number of alignments
 	* @cpuSA the SA result
 	* @numSA the number of SA ranges
 	* @h_query encoded reads
 	* @numQuery
 	* @readLength in base-pair
 	* */
	unsigned long exactMatch(SAResult &saResult, QuerySet &querySet);
	unsigned long oneMismatch(SAResult &saResult, SAMatch &saMatch, 
				QuerySet &querySet);
	unsigned long twoMismatches(SAResult &saResult, QuerySet &querySet);


	unsigned long allValid(SAResult &saResult, QuerySet &querySet, int Mode);
	unsigned long randomBest(SAResult &saResult, QuerySet &querySet);

	unsigned long numAlignment(SAResult &saResult) const;
	void report(SAResult &saResult) const;
	void setNumResultPerQuery(const int numPass1, const int numPass2);

private:
	/*constant*/
	const unsigned long _GPUBufSize;	//GPU memory, larger than _GPUBufSize
	const unsigned long _GPUResultBufSize;

	int numResultPerQueryPass1; 
	int numResultPerQueryPass2;

	/*memory buffers*/
	BWT* _d_bwt;
	BWT* _d_revbwt;
	st_MemoryBuf* _GPUMemBuf;

	/*private functions*/
	void getNumAlignmentPerRead(int* numAlignPerRead, const SAResult &saResult, 
					const QuerySet &querySet);
	/*for random best alignments*/
	void rb_updateMask(char* mask, SAResult &saResult, QuerySet &querySet);
	void rb_updateSA(SAResult &saResult, QuerySet &querySet, const char* mask);
};

#endif /*__GPU2BWT_API_H__*/
